﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Security;

using Microsoft.VisualStudio.TestTools.UITesting;
using Microsoft.VisualStudio.TestTools.UITesting.WinControls;

using CodeStream.Testing.WebAutomation.InternetExplorer;

namespace CodeStream.Testing.WebAutomation
{
    /// <summary>
    /// Implements BrowserInstance using Internet Explorer 9.
    /// </summary>
    /// <remarks>
    /// Javascript can only be enabled if the browser instance is not running in protected mode.  If it is running in protected mode, either run the application as Administrator, or add about:blank to the Trusted Sites Zone
    /// </remarks>
    [SecurityCritical]
    public class InternetExplorerInstance : BrowserInstance
    {
        private bool m_disabledJavascript;

        /// <summary>
        /// Initializes a new instance of the <see cref="InternetExplorerInstance"/> class.
        /// </summary>
        public InternetExplorerInstance() : this(true)
        { }

        /// <summary>
        /// Initializes a new instance of the <see cref="InternetExplorerInstance"/> class.
        /// </summary>
        /// <param name="scriptEnabled">If set to false, scripting is disabled in the browser instance that is created.</param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification="The class is marked SecurityCritical instead of using LinkDemands.")]
        public InternetExplorerInstance(bool scriptEnabled) : 
            base(Process.Start("iexplore.exe", "-nomerge"))
        {            
            m_disabledJavascript = !scriptEnabled;
            if (!scriptEnabled)
                SetJavascriptState(true);
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected override void Dispose(bool disposing)
        {
            if (m_disabledJavascript && Browser != null)
                SetJavascriptState(false);
            m_disabledJavascript = false;

            base.Dispose(disposing);
        }

        /// <summary>
        /// Disables or enabled javascript.
        /// </summary>
        /// <param name="disable">Disables javascript if set to true.</param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters", MessageId = "Microsoft.VisualStudio.TestTools.UITesting.Keyboard.SendKeys(System.String)")]
        private void SetJavascriptState(bool disable)
        {
            bool wasInitialized = Playback.IsInitialized;

            if (!wasInitialized)
                Playback.Initialize();

            try
            {
                using (var browserWrapper = new UIBrowserApplication(Browser) { CloseOnPlaybackCleanup = false })
                {
                    Keyboard.SendKeys("{F12}");
                    UIDevWindow devWindow = browserWrapper.DevWindow;
                    devWindow.WaitForControlExist();
                    Mouse.Click(devWindow.Menu.Disable);
                    UIDevDisableMenu disableMenu = browserWrapper.DevWindowMenu.DisableMenu;
                    disableMenu.WaitForControlExist();
                    WinMenuItem scriptMenuItem = disableMenu.Script;
                    scriptMenuItem.WaitForControlExist();

                    if (scriptMenuItem.Enabled == false)
                        throw new InvalidOperationException("Script cannot be disabled when IE is running in protected mode.  Possibly place about:blank in the trusted sites zone.");

                    if (scriptMenuItem.Checked != disable)
                        Mouse.Click(scriptMenuItem);
                    Mouse.Click(devWindow.TitleBar.Close);
                }
            }
            finally
            {
                if (!wasInitialized)
                    Playback.Cleanup();
            }
        }
    }
}
